package schema

import (
	"regexp"
	"strings"

	"github.com/pkg/errors"
)

// FieldType 字段类型枚举
type FieldType string

// 定义支持的字段类型
const (
	TypeInt      FieldType = "INT"
	TypeFloat    FieldType = "FLOAT"
	TypeVarchar  FieldType = "VARCHAR"
	TypeText     FieldType = "TEXT"
	TypeEnum     FieldType = "ENUM"
	TypeDate     FieldType = "DATE"
	TypeDatetime FieldType = "DATETIME"
	TypeArray    FieldType = "ARRAY"
	TypeMap      FieldType = "MAP"
)

// FieldRole 字段角色枚举
type FieldRole string

// 定义支持的字段角色
const (
	RolePrimary FieldRole = "PRIMARY"
	RoleForeign FieldRole = "FOREIGN"
	RoleNormal  FieldRole = "NORMAL"
	RoleFormula FieldRole = "FORMULA"
	RoleExpr    FieldRole = "EXPR"     // 新增EXPR角色
)

// Field 字段定义
type Field struct {
	Name          string      `json:"Name"`
	Comment       string      `json:"Comment"`
	Role          FieldRole   `json:"Role"`
	Type          FieldType   `json:"Type"`
	Index         bool        `json:"Index"`
	AutoIncrement bool        `json:"AutoIncrement"`
	Precision     int         `json:"Precision"`
	Scale         int         `json:"Scale"`
	Default       interface{} `json:"Default"`
	ExprField     string      `json:"ExprField"`
	DefaultExpr   string      `json:"DefaultExpr"`
	References    string      `json:"References"`
	OnDelete      string      `json:"OnDelete"`
	OnUpdate      string      `json:"OnUpdate"`
	NotNull       bool        `json:"NotNull"`
}

// Table 表定义
type Table struct {
	Name    string  `json:"Name"`
	Comment string  `json:"Comment"`
	Fields  []Field `json:"Fields"`
}

// Schema 模型定义
type Schema struct {
	Name    string  `json:"Name"`
	Comment string  `json:"Comment"`
	Tables  []Table `json:"Tables"`
}

// 名称验证正则表达式
var nameRegex = regexp.MustCompile(`^[A-Z][A-Za-z0-9]*$`)

// Validate 验证Schema的合法性
func (schema *Schema) Validate() error {
	if !nameRegex.MatchString(schema.Name) {
		return errors.Errorf("模型名称'%s'不符合规范，必须以大写字母开头且只包含字母和数字", schema.Name)
	}

	for _, table := range schema.Tables {
		if !nameRegex.MatchString(table.Name) {
			return errors.Errorf("表名称'%s'不符合规范，必须以大写字母开头且只包含字母和数字", table.Name)
		}

		for _, field := range table.Fields {
			if !nameRegex.MatchString(field.Name) {
				return errors.Errorf("字段名称'%s'不符合规范，必须以大写字母开头且只包含字母和数字", field.Name)
			}

			// 验证字段角色和类型的兼容性
			if err := validateFieldRoleAndType(field); err != nil {
				return err
			}

			// 验证外键引用
			if field.Role == RoleForeign {
				if field.References == "" {
					return errors.Errorf("外键字段'%s'必须指定References", field.Name)
				}
				parts := strings.Split(field.References, ".")
				if len(parts) != 2 {
					return errors.Errorf("外键引用格式错误，应为'Table.Field': %s", field.References)
				}
				refTable := parts[0]
				refField := parts[1]
				foundTable := false
				for _, t := range schema.Tables {
					if t.Name == refTable {
						foundTable = true
						foundField := false
						for _, f := range t.Fields {
							if f.Name == refField && f.Role == RolePrimary {
								foundField = true
								break
							}
						}
						if !foundField {
							return errors.Errorf("外键引用的字段'%s.%s'不是主键", refTable, refField)
						}
						break
					}
				}
				if !foundTable {
					return errors.Errorf("外键引用的表'%s'不存在", refTable)
				}
			}
		}
	}
	return nil
}

// 验证字段角色和类型的兼容性
func validateFieldRoleAndType(field Field) error {
	// 根据schema说明文档实现角色和类型的兼容性验证
	switch field.Role {
	case RolePrimary:
		if field.Type != TypeInt && field.Type != TypeVarchar {
			return errors.Errorf("主键字段'%s'只能是INT或VARCHAR类型", field.Name)
		}
	case RoleFormula:
		// 公式字段可以是任何类型，但需要检查表达式设置
		if field.ExprField == "" && field.DefaultExpr == "" {
			return errors.Errorf("公式字段'%s'必须设置ExprField或DefaultExpr", field.Name)
		}
	case RoleExpr:
		// EXPR字段必须是TEXT类型，用于存储表达式文本
		if field.Type != TypeText {
			return errors.Errorf("EXPR字段'%s'必须是TEXT类型", field.Name)
		}
		// EXPR字段不能设置表达式相关字段
		if field.ExprField != "" || field.DefaultExpr != "" {
			return errors.Errorf("EXPR字段'%s'不能设置ExprField或DefaultExpr", field.Name)
		}
	}
	return nil
}

// FindField 查找字段定义，返回字段和所属表名
func (s *Schema) FindField(fieldName string) (*Field, string, error) {
	for _, table := range s.Tables {
		for _, field := range table.Fields {
			if field.Name == fieldName {
				return &field, table.Name, nil
			}
		}
	}
	return nil, "", errors.Errorf("字段 '%s' 不存在", fieldName)
}

// GetTable 获取表定义
func (s *Schema) GetTable(tableName string) (*Table, error) {
	for _, table := range s.Tables {
		if table.Name == tableName {
			return &table, nil
		}
	}
	return nil, errors.Errorf("表 '%s' 不存在", tableName)
}

// HasField 检查字段是否存在
func (s *Schema) HasField(tableName, fieldName string) bool {
	table, err := s.GetTable(tableName)
	if err != nil {
		return false
	}
	
	for _, field := range table.Fields {
		if field.Name == fieldName {
			return true
		}
	}
	return false
}
